package com.swak.persistence;

import java.util.List;

import com.swak.entity.Page;
import com.swak.entity.Parameters;

/**
 * 提供基础的 CURD
 * 
 * @author lifeng
 * @date 2021年1月21日 下午3:38:41
 */
public interface BaseMapper<T, PK> {

	/**
	 * 根据主键查询：
	 * 
	 * SELECT * FROM TEST_TABLE WHERE ID = #{T.ID}
	 * 
	 * @param id
	 * @return
	 */
	T get(PK id);

	/**
	 * 选择列查询:
	 * 
	 * SELECT 
	 * ${columns} 表达式
	 * FROM TEST_TABLE WHERE 1=1
	 * ${queryCondition} 条件表达式
	 * 
	 * @param selective
	 * @return
	 */
	T getSelective(Selective selective);

	/**
	 * 根据条件查询:
	 * 
	 * SELECT * FROM TEST_TABLE WHERE 1=1
	 * ${entity} 实体解析表达式(校验实体属性不为空则作为查询条件)
	 * 
	 * @param id
	 * @return
	 */
	T getUnique(T entity);

	/**
	 * SELECT * FROM TEST_TABLE WHERE 1=1
	 * ${queryCondition} 条件表达式
	 * 
	 * @param qc
	 * @return
	 */
	T getByCondition(QueryCondition qc);

	/**
	 * 是否存在:
	 * 
	 * SELECT COUNT(1) FROM TEST_TABLE WHERE ID = #{T.ID}
	 * 
	 * @param id
	 * @return
	 */
	boolean exists(PK id);

	/**
	 * 根据条件查询个数:
	 * 
	 * SELECT COUNT(1) C FROM SYS_DUAL WHERE EXISTS ( 
	 *   SELECT 1 FROM TEST_TABLE WHERE 1=1
	 *   ${queryCondition} 条件表达式
	 * )
	 * 
	 * @param qc
	 * @return 个数
	 */
	boolean existsByCondition(QueryCondition qc);

	/**
	 * 根据条件查询:
	 * 
	 * SELECT * FROM TEST_TABLE WHERE 1=1
	 * ${entity} 实体解析表达式(校验实体属性不为空则作为查询条件)
	 * 
	 * @param id
	 * @return
	 */
	boolean existsSelective(T entity);

	/**
	 * 版本比较用于乐观锁
	 * 
	 * @param entity
	 */
	@Deprecated
	void compareVersion(T entity);

	/**
	 * 根据主键查询并锁定行:
	 * 
	 * SELECT * FROM TEST_TABLE WHERE ID = #{T.ID} FOR UPDATE
	 * 
	 * @param id
	 * @return
	 */
	T lock(PK id);

	/**
	 * 插入数据：
	 * 
	 * INSERT INTO TEST_TABLE() VALUES();
	 * 
	 * @param entity
	 * @return
	 */
	int insert(T entity);

	/**
	 * 插入数据：
	 * 
	 * INSERT(OR IGNORE) INTO TEST_TABLE(columns has value) VALUES(columns has value);
	 * 
	 * @param entity
	 * @return
	 */
	int insertive(T entity);

	/**
	 * 插入数据：
	 * 
	 * INSERT(OR IGNORE) INTO TEST_TABLE(columns has value) VALUES(columns has value);
	 * 
	 * @param entity
	 * @param ignoreIfExists 如果存在
	 * @return 
	 */
	int insertive(T entity, boolean ignoreIfExists);

	/**
	 * 插入数据
	 * 
	 * @param statementName
	 * @param entity
	 * @return
	 */
	int insert(String statementName, T entity);

	/**
	 * 插入或更新数据
	 * @see merge
	 * 
	 * @param entity
	 * @return
	 */
	@Deprecated
	int replace(T entity);

	/**
	 * 插入或更新数据
	 * @see merge
	 * 
	 * @param entity
	 * @return
	 */
	@Deprecated
	int toggle(T entity);

	/**
	 * 删除数据:
	 * 
	 * UPDATE TEST_TABLE SET DEL_FALG = 1, DEL_AT = #{t.delAt} FROM TEST_TABLE WHERE ID = #{t.id};
	 * 
	 * @param entity
	 * @return
	 */
	int delete(T entity);

	/**
	 * 删除数据：
	 * 
	 * UPDATE TEST_TABLE SET DEL_FALG = 1, DEL_AT = #{t.delAt} WHERE 1=1
	 * <if test="t.name != null">AND NAME = #{t.name}</if>
	 * 
	 * @param entity
	 * @return
	 */
	int deleteSelective(T entity);

	/**
	 * 删除数据
	 * 
	 * @param statementName
	 * @param entity
	 * @return
	 */
	int delete(String statementName, T entity);

	/**
	 * 通过主键修改所有的列：
	 * 
	 * UPDATE TEST_TABLE SET DEL_FALG = 1, DEL_AT = #{t.delAt} WHERE 1=1  AND ID = #{t.id};
	 * 
	 * @param entity
	 * @return
	 */
	int update(T entity);

	/**
	 * 通过主键修改不为空的列：
	 * 
	 * UPDATE TEST_TABLE SET 
	 * ${entity} 只修改不为空的列
	 * WHERE  ID = #{t.id};
	 * 
	 * @param entity
	 * @return
	 */
	int updateSelective(T entity);

	/**
	 * 通过查询条件设置指定列的值：
	 * 
	 * UPDATE 
	 * ${columns} 指定列设置值
	 * FROM TEST_TABLE WHERE 1=1
	 * ${queryCondition} 条件表达式
	 * 
	 * @param entity
	 * @return
	 */
	int updative(Updative updative);

	/**
	 * 自动Sql更新
	 * 
	 * @param statementName
	 * @param entity
	 * @return
	 */
	int update(String statementName, T entity);

	/**
	 * 清空选择的列: 已删除
	 * UPDATE 
	 * ${columns} 将指定的列设置为 null
	 * FROM TEST_TABLE WHERE 1=1
	 * ${queryCondition} 条件表达式
	 * 
	 * @see updative(功能和updative重合)
	 * 
	 * @param selective
	 * @return
	 */
	@Deprecated
	int clearSelective(Selective selective);

	/**
	 * 批量新增
	 * 
	 * @Title: batchInsert
	 * @Description: 批量新增
	 * @return void 返回类型
	 */
	int batchInsert(final List<T> entitys);

	/**
	 * 批量新增
	 * 
	 * @Title: batchInsert
	 * @Description: 批量新增
	 * @return void 返回类型
	 */
	int batchInsert(final String sql, final List<T> entitys);

	/**
	 * 批量修改
	 * 
	 * @Title: batchInsert
	 * @Description: 批量新增
	 * @return void 返回类型
	 */
	int batchUpdate(final List<T> entitys);

	/**
	 * 批量修改
	 * 
	 * @Title: batchInsert
	 * @Description: 批量新增
	 * @return void 返回类型
	 */
	int batchUpdate(final String statementName, final List<T> entitys);

	/**
	 * 批量删除
	 * 
	 * @Title: batchInsert
	 * @Description: 批量新增
	 */
	int batchDelete(final List<T> entitys);

	/**
	 * 条件查询
	 * 
	 * @return
	 */
	List<T> querySelective(T entity);

	/**
	 * 条件查询
	 * 
	 * @return
	 */
	List<T> queryByCondition(QueryCondition qc);

	/**
	 * 条件查询
	 * 
	 * @return
	 */
	List<T> queryByCondition(QueryCondition qc, int size);

	/**
	 * 条件查询
	 * 
	 * @return
	 */
	List<T> queryByCondition(QueryCondition qc, Parameters param);

	/**
	 * 根据条件查询个数
	 * 
	 * @param qc
	 * @return 个数
	 */
	Integer countByCondition(QueryCondition qc);

	/**
	 * 根据条件查询个数
	 * 
	 * @param qc
	 * @return 个数
	 */
	Integer countByCondition(String statementName, Object qc);

	/**
	 * 根据条件查询个数
	 * 
	 * @param qc
	 * @return 个数
	 */
	Integer countBySelective(T entity);

	/**
	 * 查询
	 * 
	 * @return
	 */
	List<T> queryForList(String statementName, Object qc);

	/**
	 * 注意：起始位置是从0开始算的约定： 填0 和1 都表示第一条 直接获取前几个
	 * 
	 * @param sql
	 * @param qc
	 * @param size
	 * @return
	 */
	List<T> queryForList(String sql, Object qc, int size);

	/**
	 * 提供分页功能的数据查询 注意:本功能的SQL语句需要有对应统计记录数方法 命名规则为:功能SQL语句名称+Stat
	 * 
	 * @param query
	 * @param param
	 * @return
	 */
	Page<T> queryForPage(QueryCondition query, Parameters param);

	/**
	 * 条件查询, 自动设置需要查询的列
	 * 
	 * @return
	 */
	List<T> querySelectiveByCondition(Selective query);

	/**
	 * 条件查询, 自动设置需要查询的列
	 * 
	 * @return
	 */
	List<T> querySelectiveByCondition(Selective query, int size);

	/**
	 * 分页查询, 自动设置需要查询的列
	 * 
	 * @param query
	 * @param param
	 * @return
	 */
	Page<T> queryForSelectivePage(Selective query, Parameters param);

	/**
	 * 查询其他类型的对象数据
	 * 
	 * @param <E>
	 * @param statementName
	 * @param entity
	 * @return
	 */
	<E> List<E> queryForGenericsList(String sql, Object query);

	/**
	 * 查询其他类型的对象数据
	 * 
	 * @param <E>
	 * @param statementName
	 * @param entity
	 * @return
	 */
	<E> List<E> queryForGenericsList(String sql, Object query, int size);

	/**
	 * 分页查询
	 * 
	 * @param listStatementName 查询分页数据列表
	 * @param countStatementName 查询总数
	 * @param qc
	 * @param param
	 * @return
	 */
	Page<T> queryForPage(String listStatementName, String countStatementName, Object qc, Parameters param);

	/**
	 * 执行统计 Sql： 必须传递唯一键值
	 * @see merge
	 * @param t
	 */
	@Deprecated
	void statistic(T t);

	/**
	 * 执行Merge Sql, 替換之前的 statistic、 toggle、 replace
	 * 返回值说明：
	 * 0: 走 update 没有需要修改的列（通过查询没有查询到类或者需要修改的列和传递的参数的值一致） 
	 *    在这里是： 需要修改的列和传递的参数的值一致
	 * 1: 走 insert 没有发生主键或唯一键冲突， 此时 实体t 中的id值和数据库一致
	 * 1: 走 update 如果指定了主键，则会直接走update
	 * 2: 走 update 发生主键或唯一键冲突且实际上发生了修改, 这是id值和数据库不一致
	 * 
	 * -------
	 * 一般情况下返回值是： 1, 2； 因為必有需要修改的值，例如 updateDate
	 * -------
	 * 使用 ON DUPLICATE KEY 来执行数据的插入或更新（必须配置唯一索引使用）
	 * 增量添加 Stat:   (CASE WHEN %s IS NULL THEN 0 ELSE %s END) + #{t.value}
	 * 开关更新 Toggle: (CASE WHEN %s IS NULL OR %s = 0 THEN 1 ELSE 0 END)
	 * 
	 * ------
	 * 注意：默认会根据是否有主键判断是否需要执行insert；
	 * @param t
	 * @return 0, 1, 2
	 */
	int merge(T t);

	/**
	 * 执行Merge Sql, 替換之前的 statistic、 toggle、 replace
	 * 
	 * @param t
	 * @param insert 为true 强制走 insert 判断主键或者唯一键冲突后走 update;
	 */
	int merge(T t, boolean insert);
}